package smallChanges.lineNumberMapping;

import java.util.Iterator;
import java.util.List;

import simpack.measure.external.simmetrics.Jaro;
import smallChanges.statements.MethodSignature;
import smallChanges.statements.SCFormalParameter;

public class RenamedMethodParameterListComparison {

	private boolean matchedParamList;
	private double normalizedParamListEditDist;
//	private int nextTypeToken;
	
	public RenamedMethodParameterListComparison(
	        MethodSignature left, 
	        MethodSignature right)
	{
	    // TODO move the getNumFormals/getFormalParamsImage methods into
	    // methodSignature and integrate these two constructors
	    //FakeMethodSignature left=(FakeMethodSignature)realLeft;
	    //FakeMethodSignature right=(FakeMethodSignature)realRight;
	    matchedParamList = true;
	    
        /* a normalizedParamListEditDist of 1 mean
         * NO SIMILARITY
         */
        this.normalizedParamListEditDist = 1;
        
        /* 
         * If each method has a parameter list
         * use Jaro comparison to determine how
         * similar the lists are.  
         * 
         * Since Jaro can give high similarity values for
         * parameter lists with different number of 
         * parameters, add to the result the normalized
         * difference between the sizes of the two lists.
         * 
         */
        
        if ( left.getNumFormalParams() != 0 && right.getNumFormalParams() !=0)
        {
            /* need to tokenreplace the TYPES but not the NAMES */
            //HashMap<String, String> typeTokenMapping = new HashMap<String,String>();
            //String typeTokens="\"~!@#$%^&*()-+{}|\\/?,.<>;:'` "; // 30 types
            //nextTypeToken = 0;
            Jaro jaro = new Jaro(left.getTypeOnlyFormalParamsImage(), right.getTypeOnlyFormalParamsImage());
            		//paramListString(left.getFormalParameterList()/*.getFormalParamsImage()*/),
            		//paramListString(right.getFormalParameterList()/*.getFormalParamsImage()*/));
    
            jaro.calculate();
            normalizedParamListEditDist = 1-jaro.getSimilarity();
            
            double sizeDiff = (Math.abs(left.getNumFormalParams() - right.getNumFormalParams())) /
            ((double) (left.getNumFormalParams() + right.getNumFormalParams()));
            
            normalizedParamListEditDist += sizeDiff;
            
            if (normalizedParamListEditDist > 1.0)
            {
                normalizedParamListEditDist = 1.0;
            }
        }
        //else if( left.getFormalParameterList() != null)
        else if( left.getNumFormalParams() != 0)
        {
            //all are removals
            matchedParamList = false;
        }
        else if( right.getNumFormalParams() != 0)
        {
            //all are removals
            matchedParamList = false;           
        }
	}
	
//	public RenamedMethodParameterListComparison(
//	        MethodSignature left, 
//	        MethodSignature right,
//	        boolean b)
//	{
//	    if (true) throw new RuntimeException("Don't use this constructor");
//	    // This is the old constructor that is not compatible
//	    // with FakeMethodSignature
//	    matchedParamList = true;
//	
//		/* a normalizedParamListEditDist of 1 mean
//		 * NO SIMILARITY
//		 */
//		this.normalizedParamListEditDist = 1;
//		
//		/* 
//		 * If each method has a parameter list
//		 * use Jaro comparison to determine how
//		 * similar the lists are.  
//		 * 
//		 * Since Jaro can give high similarity values for
//		 * parameter lists with different number of 
//		 * parameters, add to the result the normalized
//		 * difference between the sizes of the two lists.
//		 * 
//		 */
//		if ( left.getFormalParameterList().size() != 0 && right.getFormalParameterList().size() !=0)
//		{
//			/* need to tokenreplace the TYPES but not the NAMES */
//			//HashMap<String, String> typeTokenMapping = new HashMap<String,String>();
//			//String typeTokens="\"~!@#$%^&*()-+{}|\\/?,.<>;:'` "; // 30 types
//			//nextTypeToken = 0;
//			
//			Jaro jaro = new Jaro(paramListString(left.getFormalParameterList()/*, typeTokenMapping, typeTokens*/),
//					paramListString(right.getFormalParameterList()/*, typeTokenMapping, typeTokens*/));
//	
//			jaro.calculate();
//			normalizedParamListEditDist = 1-jaro.getSimilarity();
//			
//			double sizeDiff = (Math.abs(left.getFormalParameterList().size() - right.getFormalParameterList().size())) /
//			((double) (left.getFormalParameterList().size() + right.getFormalParameterList().size()));
//			
//			normalizedParamListEditDist += sizeDiff;
//			
//			if (normalizedParamListEditDist > 1.0)
//			{
//				normalizedParamListEditDist = 1.0;
//			}
//			
//
//		}
//		else if( left.getFormalParameterList() != null)
//		{
//			//all are removals
//			matchedParamList = false;
//		}
//		else if( right.getFormalParameterList() != null)
//		{
//			//all are removals
//			matchedParamList = false;			
//		}
//	}
	private String paramListString(List<SCFormalParameter> paramList /*, HashMap<String, String> typeTokenMapping,
			String typeTokens*/)
	{
		String retVal = new String();
		
		Iterator<SCFormalParameter> iter = paramList.iterator();
		
		while(iter.hasNext())
		{
			SCFormalParameter param = iter.next();
			/*String token;
			if( typeTokenMapping.containsKey(param.getType()) )
			{
				token = typeTokenMapping.get(param.getType());
			}
			else
			{
				token = String.valueOf(typeTokens.charAt(nextTypeToken));
				token = String.valueOf(typeTokens.charAt(nextTypeToken));
				token = String.valueOf(typeTokens.charAt(nextTypeToken++));
			}
			retVal += token;		
			*/
			retVal += param.getType();
			if( param.isArrayType() )
			{
				retVal += "[]";
			}
			//retVal += param.getName();
			
			//retVal += iter.next().toString();//+ " ";
		}
		return retVal;
	}
	
	public double getNormalizedParamListEditDist()
	{
		return normalizedParamListEditDist;
	}
	
	public boolean matched()
	{
		return matchedParamList;
	}
}
